#ifndef __CLX_LOOGER_HPP__
#define __CLX_LOOGER_HPP__ 

#include "util.hpp"
#include "message.hpp"
#include "sink.hpp"
#include "format.hpp"
#include "looper.hpp"

#include <thread>
#include <mutex>
#include <atomic>
#include <cstdarg>

namespace clxlog {
  class Logger {
    public:
    using ptr = std::shared_ptr<Logger>;
    Logger(const std::string& logger_name, LogLevel::value& limit_level, Formatter::ptr& formatter, std::vector<Sink::ptr>& sinks)
      : _limit_level(limit_level), _logger_name(logger_name), _formatter(formatter), _sinks(sinks.begin(), sinks.end()) {}

    std::string get_name() { return _logger_name; }

    void debug(const std::string& file, size_t line, const std::string format_str, ...) {
      // 判断是否符合输出条件
      if (LogLevel::value::DEBUG < _limit_level) return;
      // 获取用户日志信息
      va_list ap;
      va_start(ap, format_str);
      char* usr_msg = nullptr;
      vasprintf(&usr_msg, format_str.c_str(), ap);
      va_end(ap);

      // 构建LogMsg
      LogMsg msg(LogLevel::value::DEBUG, line, file, _logger_name, usr_msg);
      free(usr_msg);
      // 将LogMsg对象进行格式化
      std::string logstr = _formatter->format(msg);
      // 调用log函数进行落地
      log(logstr.c_str(), logstr.size());
    }
    protected:
    virtual void log(const char* logstr, size_t len) = 0;

    protected:
      std::mutex _mtx;                            // 一个日志器可能会被多个线程同时访问
      std::atomic<LogLevel::value> _limit_level;  // 日志等级需要频繁访问 
      std::string _logger_name;
      Formatter::ptr _formatter;
      std::vector<Sink::ptr> _sinks;
  };

  class SynchLogger : public Logger {
    virtual void log(const char* logstr, size_t len) override{
      std::unique_lock<std::mutex> mtx(_mtx);
      for (auto& sink : _sinks) {
        sink->log(logstr, len);
      }
    }
  };

  class AsynchLogger : public Logger {
    public:
    AsynchLogger(const std::string& logger_name, LogLevel::value& limit_level, Formatter::ptr& formatter, std::vector<Sink::ptr>& sinks, AsynchType looper_type) 
      : Logger(logger_name, limit_level, formatter, sinks), 
      _looper(std::make_shared<AsynchLooper>(looper_type, std::bind(&AsynchLogger::realSink, this, std::placeholders::_1))) {}
      
      virtual void log(const char* logstr, size_t len) override{
        _looper->push(logstr, len);
      }

      void realSink(Buffer& buffer) {
        if (_sinks.empty()) return;
        for (auto sink : _sinks) {
          sink->log(buffer.begin(), buffer.readAbleSize());
        }
        return;
      }
    private:
      AsynchLooper::ptr _looper;
  };


  enum class LoggerType  {
    SYNCH_LOGGER,
    ASYNCH_LOGGER
  };

  class LoggerBuild {

  };
}

#endif 
